package com.supreme.cacheserver.controller;

import com.alibaba.fastjson.JSONObject;
import com.github.benmanes.caffeine.cache.Cache;
import com.supreme.cacheserver.service.OmsDeptService;
import com.supreme.common.dto.OmsDept;
import com.supreme.common.dto.ResString;
import com.supreme.commonboot.utils.AjaxResp;
import com.supreme.commonentity.mysql.primary.SysDept;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import javax.annotation.Resource;
import java.net.URI;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RestController
@RequestMapping(value = "oms-dept")
public class OmsDeptController {

    @Resource
    private RedisTemplate<String, OmsDept> redisTemplate;

    @Resource
    private Cache<String, List<OmsDept>> caffeineCacheList;

    @Resource
    private Cache<String, Map<String, OmsDept>> caffeineCacheHash;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private OmsDeptService omsDeptService;

    @GetMapping(value = "getOmsDeptListFromCaffeine")
    public AjaxResp getOmsDeptListFromCaffeine() {
        List<OmsDept> omsDeptList = caffeineCacheList.get("DEPT_LIST", s -> redisTemplate.opsForList().range(s, 0, -1));
        return AjaxResp.instance(omsDeptList);
    }

    @GetMapping(value = "getOmsDeptHashFromCaffeine")
    public AjaxResp getOmsDeptHashFromCaffeine() {
        Map<String, OmsDept> deptHash = caffeineCacheHash.get("DEPT_HASH", s -> {
            List<OmsDept> omsDeptList = redisTemplate.opsForList().range("DEPT_LIST", 0, -1);
            if (Objects.nonNull(omsDeptList)) {
                return omsDeptList.parallelStream().collect(Collectors.toMap(OmsDept::getStoreCode, Function.identity()));
            } else {
                return new HashMap<>();
            }
        });
        return AjaxResp.instance(deptHash);
    }

    @GetMapping(value = "setOmsDept/{storeCode}")
    public AjaxResp setOmsDept(@PathVariable(value = "storeCode") String storeCode) {
        CompletableFuture<List<OmsDept>> completableFuture = CompletableFuture.supplyAsync(() -> {
            URI requestUri = UriComponentsBuilder.fromHttpUrl("http://localhost:9633/omni/test/biz/deptList")
                    .queryParam("syncType", 1)
                    .queryParam("storeCode", storeCode)
                    .build().encode().toUri();
            String stringResponse = restTemplate.getForObject(requestUri, String.class);
            return stringResponse;
        }).thenApply(s -> {
            ResString resString = JSONObject.parseObject(s, ResString.class);
            OmsDept[] omsDeptArray = JSONObject.parseObject(resString.getData(), OmsDept[].class);
            return Stream.of(omsDeptArray).collect(Collectors.toList());
        }).handle((omsDeptList, throwable) -> {
            for (OmsDept omsDept : omsDeptList) {
                redisTemplate.opsForValue().set("DEPT:" + omsDept.getStoreCode(), omsDept);
            }
            return omsDeptList;
        });

        List<OmsDept> omsDeptList;
        try {
            omsDeptList = completableFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return AjaxResp.instance(omsDeptList);
    }

    @GetMapping(value = "getOmsDeptList")
    public AjaxResp getOmsDeptList() {
        CompletableFuture<List<OmsDept>> completableFuture = CompletableFuture.supplyAsync(() -> {
            URI requestUri = UriComponentsBuilder.fromHttpUrl("http://localhost:9633/omni/test/biz/deptList")
                    .queryParam("syncType", 1)
                    .build().encode().toUri();
            String stringResponse = restTemplate.getForObject(requestUri, String.class);
            return stringResponse;
        }).thenApply(s -> {
            ResString resString = JSONObject.parseObject(s, ResString.class);
            return JSONObject.parseObject(resString.getData(), OmsDept[].class);
        }).handle((omsDeptArray, throwable) -> Stream.of(omsDeptArray).collect(Collectors.toList()));

        List<OmsDept> omsDeptList;
        try {
            omsDeptList = completableFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return AjaxResp.instance(omsDeptList);
    }

    @PostMapping(value = "setOmsDeptListToRedis")
    public AjaxResp setOmsDeptListToRedis() {
        CompletableFuture<OmsDept[]> completableFuture = CompletableFuture.supplyAsync(() -> {
            URI requestUri = UriComponentsBuilder.fromHttpUrl("http://localhost:9633/omni/test/biz/deptList")
                    .queryParam("syncType", 1)
                    .build().encode().toUri();
            String stringResponse = restTemplate.getForObject(requestUri, String.class);
            return stringResponse;
        }).handle((s, throwable) -> {
            ResString resString = JSONObject.parseObject(s, ResString.class);
            return JSONObject.parseObject(resString.getData(), OmsDept[].class);
        });

        List<OmsDept> omsDeptList;
        try {
            OmsDept[] omsDeptArray = completableFuture.get();

            redisTemplate.delete("DEPT_LIST");
            redisTemplate.opsForList().rightPushAll("DEPT_LIST", omsDeptArray);

            Map<String, OmsDept> sysDeptHash = Stream.of(omsDeptArray).collect(Collectors.toMap(OmsDept::getStoreCode, Function.identity()));
            redisTemplate.delete("DEPT_HASH");
            redisTemplate.opsForHash().putAll("DEPT_HASH", sysDeptHash);

            omsDeptList = Stream.of(omsDeptArray).collect(Collectors.toList());

        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return AjaxResp.instance(omsDeptList);
    }

    @GetMapping(value = "getOmsDeptListFromRedis")
    public AjaxResp getOmsDeptListFromRedis() {
        List<OmsDept> deptList = omsDeptService.getOmsDeptListFromRedis("DEPT_LIST");
        return AjaxResp.instance(deptList);
    }

    @GetMapping(value = "loopFindSysDeptFromLocal/{queryType}")
    public AjaxResp loopFindSysDeptFromLocal(@PathVariable(value = "queryType") Integer queryType) {
        CompletableFuture<List<SysDept>> completableFuture = CompletableFuture.supplyAsync(() -> {
            URI requestUri = UriComponentsBuilder.fromHttpUrl("http://localhost:9633/omni/test/biz/deptList")
                    .queryParam("syncType", 1)
                    .build().encode().toUri();
            String stringResponse = restTemplate.getForObject(requestUri, String.class);
            return stringResponse;
        }).handle((s, throwable) -> {
            ResString resString = JSONObject.parseObject(s, ResString.class);
            SysDept[] sysDeptArray = JSONObject.parseObject(resString.getData(), SysDept[].class);
            return Stream.of(sysDeptArray).collect(Collectors.toList());
        });

        List<SysDept> sysDeptList;
        long totalTimeMillis;
        try {
            sysDeptList = completableFuture.get();
            sysDeptList = sysDeptList.stream().filter(sysDept -> sysDept.getStoreCode().length() > 4).collect(Collectors.toList());
            totalTimeMillis = omsDeptService.loopFindSysDeptFromLocal(sysDeptList, queryType);
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        return AjaxResp.instance(totalTimeMillis);
    }

    @PostMapping(value = "setOmsDeptListToMysql")
    public AjaxResp setOmsDeptListToMysql(@RequestParam(value = "insertType") Integer insertType) {
        CompletableFuture<List<SysDept>> completableFuture = CompletableFuture.supplyAsync(() -> {
            URI requestUri = UriComponentsBuilder.fromHttpUrl("http://localhost:9633/omni/test/biz/deptList")
                    .queryParam("syncType", 1)
                    .build().encode().toUri();
            String stringResponse = restTemplate.getForObject(requestUri, String.class);
            return stringResponse;
        }).handle((s, throwable) -> {
            ResString resString = JSONObject.parseObject(s, ResString.class);
            SysDept[] sysDeptArray = JSONObject.parseObject(resString.getData(), SysDept[].class);
            return Stream.of(sysDeptArray).collect(Collectors.toList());
        });

        List<SysDept> sysDeptList;
        try {
            sysDeptList = completableFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

        long totalTimeMillis = 0;
        switch (insertType) {
            case 1:
                totalTimeMillis = omsDeptService.batchInsertSysDeptBySingle(sysDeptList);
                break;

            case 2:
                totalTimeMillis = omsDeptService.batchInsertSysDeptByMapper(sysDeptList);
                break;

            case 3:
                totalTimeMillis = omsDeptService.batchInsertSysDeptByService(sysDeptList);
                break;

            case 4:
                totalTimeMillis = omsDeptService.batchInsertSysDeptBySqlSession(sysDeptList);
                break;
        }

        return AjaxResp.instance(sysDeptList).append("totalTimeMillis", totalTimeMillis);
    }
}
